//
// Created by 崔世强 on 2018/3/24.
// Copyright (c) 2018 Facebook. All rights reserved.
//

import Foundation
import WCDBSwift

class GroupDao {
    
    static func updateAllDeleted() throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.deleted = true
        try db.update(table: Group.table, on: Group.CodingKeys.deleted, with: row)
    }
    
    static func updateGroupName(_ groupId: Int, name: String?) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.groupId = groupId
        row.name = name
        try db.update(table: Group.table, on: Group.CodingKeys.name, with: row, where: Group.CodingKeys.groupId == groupId)
    }
    
    class func updateKickout(_ groupId: Int, kickout: Bool) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.groupId = groupId
        row.kickout = kickout
        try db.update(table: Group.table, on: Group.CodingKeys.kickout, with: row, where: Group.CodingKeys.groupId == groupId)
    }
    
    static func getGroup(_ id: Int!) throws -> Group? {
        let db = SQLiteHelper.getDb()
        let group: Group? = try db.getObject(on: Group.CodingKeys.all, fromTable: Group.table, where: Group.CodingKeys.groupId == id)
        return group
    }
    
    static func getMembers(_ id: Int, limit: Int) throws -> [GroupMember] {
        let db = SQLiteHelper.getDb()
        var returnMembers = [GroupMember]()
        returnMembers = try db.getObjects(on: GroupMember.CodingKeys.all, fromTable: GroupMember.table,
                                          where: GroupMember.CodingKeys.groupId == id && GroupMember.CodingKeys.deleted == false,
                                          orderBy:[GroupMember.CodingKeys.memberType.asOrder()],
                                          limit: (limit==0 ? 1000000 : limit))
        return returnMembers
    }
    
    static func getMemberIds(_ id: Int, limit: Int) throws -> [Int] {
        let db = SQLiteHelper.getDb()
        var returnMembers = [Int]()
        let members: [GroupMember] = try db.getObjects(on: GroupMember.CodingKeys.all, fromTable: GroupMember.table,
                                                       where: GroupMember.CodingKeys.groupId == id && GroupMember.CodingKeys.deleted == false,
                                                       limit: (limit==0 ? 1000000 : limit))
        for member in members {
            returnMembers.append(member.userId)
        }
        return returnMembers
    }
    
    static func delete(_ groupId: Int, userIds: [Int]) throws {
        let db = SQLiteHelper.getDb()
        let row = GroupMember()
        row.deleted = true
        try db.update(table: GroupMember.table,
                      on: GroupMember.CodingKeys.deleted,
                      with: row,
                      where: GroupMember.CodingKeys.groupId == groupId && GroupMember.CodingKeys.userId.asExpression().in(userIds))
    }
    
    class func insert(_ member: GroupMember) throws -> Int {
        let db = SQLiteHelper.getDb()
        try db.insert([member], intoTable: GroupMember.table)
        return member.lastInsertedRowID
    }
    
    class func updateMember(_ groupId: Int, userId: Int, deleted: Bool) throws {
        let db = SQLiteHelper.getDb()
        let row = GroupMember()
        row.deleted = deleted
        try db.update(table: GroupMember.table, on: GroupMember.CodingKeys.deleted, with: row, where: GroupMember.CodingKeys.groupId == groupId && GroupMember.CodingKeys.userId == userId)
    }
    
    static func updateMemberNickName(_ groupId: Int, userId: Int, nickName: String) throws {
        let db = SQLiteHelper.getDb()
        let row = GroupMember()
        row.nickName = nickName
        try db.update(table: GroupMember.table, on: GroupMember.CodingKeys.nickName, with: row, where: GroupMember.CodingKeys.groupId == groupId && GroupMember.CodingKeys.userId == userId)
    }
    
    static func updateMuteAll(_ id: Int, muteAll: Bool) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.groupId = id
        row.mute = muteAll
        try db.update(table: Group.table, on: Group.CodingKeys.mute, with: row, where: Group.CodingKeys.groupId == id)
    }
    
    static func updateNoDisturb(_ id: Int, noDisturb: Bool) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.groupId = id
        row.noDisturb = noDisturb
        try db.update(table: Group.table, on: Group.CodingKeys.noDisturb, with: row, where: Group.CodingKeys.groupId == id)
    }
    
    static func updateDelete(_ id: Int, deleted: Bool) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.groupId = id
        row.deleted = deleted
        try db.update(table: Group.table, on: Group.CodingKeys.deleted, with: row, where: Group.CodingKeys.groupId == id)
    }
    
    class func quit(_ id: Int) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.groupId = id
        row.deleted = true
        try db.update(table: Group.table, on: Group.CodingKeys.deleted, with: row, where: Group.CodingKeys.groupId == id)
    }
    
    static func updateTop(_ id: Int, top: Bool) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.groupId = id
        row.top = top
        try db.update(table: Group.table, on: Group.CodingKeys.top, with: row, where: Group.CodingKeys.groupId == id)
    }
    
    static func getMember(_ groupId: Int, userId: Int) throws -> GroupMember? {
        let db = SQLiteHelper.getDb()
        let returnMember: GroupMember? = try db.getObject(on: GroupMember.CodingKeys.all, fromTable: GroupMember.table,
                                                          where: GroupMember.CodingKeys.groupId == groupId && GroupMember.CodingKeys.deleted == false && GroupMember.CodingKeys.userId == userId)
        return returnMember
    }
    
    static func getMemberWithoutDeleted(_ groupId: Int, userId: Int) throws -> GroupMember? {
        let db = SQLiteHelper.getDb()
        let returnMember: GroupMember? = try db.getObject(on: GroupMember.CodingKeys.all, fromTable: GroupMember.table,
                                                          where: GroupMember.CodingKeys.groupId == groupId && GroupMember.CodingKeys.userId == userId)
        return returnMember
    }
    
    class func updateAnnouncement(_ groupId: Int, announcement: String) throws {
        let db = SQLiteHelper.getDb()
        let row = Group()
        row.announcement = announcement
        try db.update(table: Group.table, on: Group.CodingKeys.announcement, with: row, where: Group.CodingKeys.groupId == groupId)
    }
    
    static func getAllOfficialGroups() throws -> [Group] {
        let db = Database(at: AppStatusManager.instance.urlForUserDB ?? URL(fileURLWithPath: ""))
        let groups: [Group] = try db.getObjects(on: Group.CodingKeys.all,
                                                fromTable: Group.table,
                                                where: Group.CodingKeys.groupType == GroupType.official && Group.CodingKeys.deleted == false,
                                                orderBy: [Group.Properties.groupId])
        return groups
    }
    
    static func createNewGroup(groupId:Int, name:String?, type: GroupType, createUserId:Int, ids: [Int]) throws -> Group {
        if let groupInDb = try getGroup(groupId) {
            return groupInDb
        }
        let group = Group()
        let db = SQLiteHelper.getDb()
        group.groupId = groupId
        group.name = name
        group.groupType = type
        group.owner = createUserId
        try db.insert([group], intoTable: Group.table)
        for id in ids {
            let groupMember = GroupMember()
            groupMember.userId = id
            groupMember.groupId = groupId
            _ = try self.insert(groupMember)
        }
        let me = GroupMember()
        me.userId = createUserId
        me.groupId = groupId
        me.me = true
        me.memberType = .owner
        _ = try self.insert(me)
        return group
    }
}
